/* This module show the region to the user, so that he might choose in what
 * city he wants to play. */

#include "ui_region.h"

#include <assert.h>
#include <math.h>
#include <stdlib.h>

#include "global.h"
#include "cursors.h"
#include "dialog.h"
#include "palette.h"
#include "text.h"
#include "water.h"

// Constants
static const int BORDER = 40;       // Space empty in the four sides of the image.
static const int TILE_SIZE = 2;     // Size of each tile.
static const float INCLINATION = 3; // Region image inclination degree.
static const int DIRT_HEIGHT = 35;  // How big is the land below the city (brown area)

// Used to set the map position on the screen
static int rel_x, rel_y;
static int last_x, last_y;

// Images and palette
static SDL_Surface *reg_sf = NULL,
		   *region_name = NULL,
		   *msg = NULL;
static SDL_Color color[256];
enum Colors { R_BACKGROUND = 20, GRASS_1, GRASS_2, GRASS_3, DIRT_1, 
	DIRT_2,	TREE_1, TREE_2, CITY_BORDER, R_WATER, UNDERWATER, BUTTON_BORDER 
};
         
// The given region
static Region* region = NULL;

// Object that controls the water palette
static Water* water = NULL;

// The city the user chose to play
static City* chosen_city = NULL;

// Screen buttons
void reboot_region();
void delete_region();
void rename_region();
void back();
static int buttons_w = 0;
static struct Button {
	char* text;
	void(*function)();
	SDL_Surface* sf;
	SDL_Rect pos;
} buttons[] = { 
	{ gettext_noop("Reboot region"), &reboot_region },
	{ gettext_noop("Delete region"), &delete_region },
	{ gettext_noop("Rename region"), &rename_region },
	{ gettext_noop("Back to main menu"), &back },
	{ NULL }
};



// initialize images used on this screen
void initialize_images()
{
	// create message images
	Pencil p = { screen, editundo14, (SDL_Color){255,255,255}, (SDL_Color){0,0,0}};
	msg = dbl_text(p, 0, _("Please choose a city from the map."));
	region_name = dbl_text(p, 0, region->name);

	// create button images
	int buttons_h = 0;
	int i=0;
	while(buttons[i].text != NULL)
	{
		int w = text_width(p, _(buttons[i].text));
		if(w > buttons_w)
			buttons_w = w;
		i++;
	}
	int y = 30;
	i = 0;
	buttons_h = TTF_FontLineSkip(p.font) + 12;
	while(buttons[i].text != NULL)
	{
		buttons[i].pos = (SDL_Rect) { screen->w - buttons_w - 30, y, 
			buttons_w + 20, buttons_h };
		buttons[i].sf = dbl_text(p, 0, _(buttons[i].text));
		y += buttons_h + 8;
		i++;
	}
}


// Draw all the images in the screen, and flip.
static void draw_screen()
{
	// map
	SDL_BlitSurface(reg_sf, NULL, screen, &(SDL_Rect) { rel_x, rel_y });

	// screen messages
	SDL_BlitSurface(region_name, NULL, screen, &(SDL_Rect) { 20, 20 });
	SDL_BlitSurface(msg, NULL, screen, &(SDL_Rect) { 20, screen->h-30 });

	// draw buttons	
	int i=0;
	while(buttons[i].text != NULL)
	{
		buttons[i].pos.x = screen->w - buttons_w - 30; // in case of redraw
		SDL_FillRect(screen, &buttons[i].pos, BUTTON_BORDER);
		SDL_FillRect(screen, &(SDL_Rect) {
				buttons[i].pos.x+1,
				buttons[i].pos.y+1,
				buttons[i].pos.w-2,
				buttons[i].pos.h-2 }, R_BACKGROUND);
		SDL_BlitSurface(buttons[i].sf, NULL, screen, &(SDL_Rect) {
				buttons[i].pos.x + 10,
				buttons[i].pos.y + 6 });
		i++;
	}
	SDL_Flip(screen);
}


// Calculate the depth of a water tile
static int tile_depth(Region* r, int x, int y)
{
	if(r->data[x + (y * r->h)] != WATER)
		return 0;
	
	int depth=0;
	while((++depth) < 30)
	{
		if(x+depth < region->w)
			if(r->data[(x+depth) + (y * r->h)] != WATER)
				break;
		if(x-depth >= 0)
			if(r->data[(x-depth) + (y * r->h)] != WATER)
				break;
		if(y+depth < region->h)
			if(r->data[x + ((y+depth) * r->h)] != WATER)
				break;
		if(y-depth >= 0)
			if(r->data[x + ((y-depth) * r->h)] != WATER)
				break;
	}
	return log(depth+1)*8;
}


// Draw one tile on the map.
static void draw_tile(int tx, int ty)
{
	Uint8* pixels = ((Uint8*)reg_sf->pixels);
	int xpos = BORDER + (tx * TILE_SIZE) + (ty * TILE_SIZE / INCLINATION);
	int ypos = BORDER + (ty * TILE_SIZE);

	int x, y;

	// lock surface
	if(SDL_MUSTLOCK(reg_sf))
		if(!SDL_LockSurface(reg_sf))
			ui_error(_("Error locking surface."));

	// draw tile
	switch(region->data[tx+(ty*region->h)])
	{
		case LAND:
			for(x=xpos; x<xpos+TILE_SIZE; x++)
				for(y=ypos; y<ypos+TILE_SIZE; y++)
					pixels[x+y*reg_sf->pitch] = GRASS_1 + 
						(rand() % 3);
			break;
		case TREES:
			pixels[xpos+1+((ypos-2)*reg_sf->pitch)] = TREE_2;
			pixels[xpos+((ypos-1)*reg_sf->pitch)] = TREE_2;
			pixels[xpos+1+((ypos-1)*reg_sf->pitch)] = TREE_2;
			pixels[xpos+(ypos*reg_sf->pitch)] = TREE_2;
			pixels[xpos+1+(ypos*reg_sf->pitch)] = TREE_2;
			pixels[xpos+((ypos+1)*reg_sf->pitch)] = TREE_2;
			pixels[xpos+((ypos+2)*reg_sf->pitch)] = TREE_1;
			pixels[xpos+1+((ypos+1)*reg_sf->pitch)] = GRASS_2;
			break;
		case WATER:
			SDL_FillRect(reg_sf, &(SDL_Rect) { xpos, ypos, 
				TILE_SIZE, TILE_SIZE }, R_WATER);
			break;	
	}

	// draw underground
	if(tx == 0 || ty == (region->h-1))
	{
		// discover water depth
		int depth = tile_depth(region, tx, ty);

		for(y=(ypos+1); y<(ypos+DIRT_HEIGHT); y++)
		{
			if(depth > 0)
			{
				pixels[xpos+y*reg_sf->pitch] = UNDERWATER;
				pixels[xpos+1+y*reg_sf->pitch] = UNDERWATER;
			}
			else
			{
				pixels[xpos+y*reg_sf->pitch] = rand() % 2 
					? DIRT_1 
					: DIRT_2;
				pixels[xpos+1+y*reg_sf->pitch] = rand() % 2 
					? DIRT_1 
					: DIRT_2;
			}
			depth--;
		}
	}

	// draw city borders
	if((ty % (region->h / 4) == 0 && ty != 0 && ty <= (region->h / 2))
	|| (tx % (region->w / 4) == 0 && tx != 0 && ty <= (region->h / 4))
	|| (tx % (region->w / 2) == 0 && tx != 0 && ty <= (region->h / 2)))
	{
		pixels[xpos+ypos*reg_sf->pitch] = CITY_BORDER;
		pixels[xpos+1+(ypos+1)*reg_sf->pitch] = CITY_BORDER;
	}

	// unlock surface
	if(SDL_MUSTLOCK(reg_sf))
		SDL_UnlockSurface(reg_sf);
}


// Draw the region image.
static void draw_region()
{
	int w = ((region->w + (region->h / INCLINATION)) * TILE_SIZE) + (BORDER * 2);
	int h = (region->h * TILE_SIZE) + (BORDER * 2);

	// create image & draw background
	if(reg_sf)
		SDL_FreeSurface(reg_sf);
	reg_sf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
	SDL_SetPalette(reg_sf, SDL_LOGPAL|SDL_PHYSPAL, color, 0, 255);

	SDL_FillRect(reg_sf, NULL, R_BACKGROUND);

	// draw map
	int tx, ty;
	for(tx=0; tx<region->w; tx++)
		for(ty=0; ty<region->h; ty++)
			draw_tile(tx, ty);

	// write city names
	int i;
	for(i=0; i<8; i++)
		if(region->city_names[i])
		{
			Pencil p = { reg_sf, pixChicago8, 
				(SDL_Color){255,255,255}, (SDL_Color){0,0,0} };
			SDL_Surface* sf = dbl_text(p, 0, region->city_names[i]);
			tx = ((i <= 3) ? (region->w * (i*2+1) / 8)
				       : ((i <= 5) ? (((region->w) * (i*4-14)) / 8)
					           : (region->w / 2)));
			ty = ((i == 6) ? (region->h * 11 / 16)
				       : ((i >= 4) ? (region->h * 3 / 8)
					           : (region->h * 1 / 8)));
			int xpos = BORDER + (tx * TILE_SIZE) + 
					(ty * TILE_SIZE / INCLINATION);
			int ypos = BORDER + (ty * TILE_SIZE);
			SDL_BlitSurface(sf, NULL, reg_sf, &(SDL_Rect) {
					xpos - (sf->w / 2),
					ypos - (sf->h / 2)});
			SDL_FreeSurface(sf);
		}

	// replace water pixels
	water_replace(water, reg_sf, R_WATER);
}


// Create the palette for this screen.
static void setup_ui_region_palette()
{
	setup_palette(screen);
	load_default_palette(color);

	color[R_BACKGROUND] = (SDL_Color) { 182, 182, 255 };
	color[GRASS_1] = (SDL_Color) { 46, 119, 46 };
	color[GRASS_2] = (SDL_Color) { 66, 136, 66 };
	color[GRASS_3] = (SDL_Color) { 79, 152, 79 };
	color[DIRT_1]  = (SDL_Color) { 89, 53, 16 };
	color[DIRT_2]  = (SDL_Color) { 99, 63, 26 };
	color[TREE_1]  = (SDL_Color) { 73, 36, 0 };
	color[TREE_2]  = (SDL_Color) { 0, 92, 0 };
	color[R_WATER] = (SDL_Color) { 0, 0, 168 };
	color[UNDERWATER] = (SDL_Color) { 60,  60, 160 };
	color[CITY_BORDER] = (SDL_Color) { 255, 255, 128 };
	color[BUTTON_BORDER] = (SDL_Color) { 102, 102, 185 };

	// water palette
	if(water)
		free_water(water);
	water = water_init(screen, color, (SDL_Color){  60,  60, 160 },
			                  (SDL_Color){  80,  80, 255 }, 160);

	SDL_SetPalette(screen, SDL_LOGPAL|SDL_PHYSPAL, color, 0, 255);
}


// The user selected one of the cities.
static void create_city(int n)
{
	if(region->city_names[n-1])
	{
		cursor_saving();
		chosen_city = load_city(region, n);
		cursor_normal();
	}
	else
	{
		bool reply;
		char name[40]; // TODO - suggest
again:
		strcpy(name, "");
		reply = input(QUESTION, name, 40, true, 
				_("What will be the name of the new city?"));
		if(!reply)
			return;
		if(strcmp(name, "") == 0)
		{
			message(WARNING, "Please give a name to the city.");
			goto again;
		}

		cursor_saving();
		chosen_city = new_city(region, name, n);
		cursor_normal();
	}
}


// The user clicked the button
static void mouse_button(SDL_MouseButtonEvent e)
{
	// check if we're clicking the buttons
	int i=0;
	while(buttons[i].text)
	{
		if(e.x >= buttons[i].pos.x 
		&& e.x < (buttons[i].pos.x + buttons[i].pos.w)
		&& e.y >= buttons[i].pos.y 
		&& e.y < (buttons[i].pos.y + buttons[i].pos.h))
		{
			buttons[i].function();
			return;
		}
		i++;
	}

	// find out position on the map
	int x = (e.x - rel_x - BORDER) / TILE_SIZE - (((e.y - rel_y - BORDER) / TILE_SIZE / INCLINATION));
	int y = (e.y - rel_y - BORDER) / TILE_SIZE;

	int choice = -1;
	if(x >= 0 && y >= 0 && x <= region->w && y <= region->h)
	{
		switch(y / (region->h / 4))
		{
			case 0:
				choice = (x / (region->w / 4)) + 1;
				break;
			case 1:
				choice = (x / (region->w / 2)) + 5;
				break;
			case 2: case 3:
				choice = 7;
				break;
			default:
				break;
		}

		create_city(choice);
	}
}


// The user dragged the map.
static void mouse_motion(SDL_MouseMotionEvent e)
{
	int xrel = e.x - last_x;
	int yrel = e.y - last_y;
                
	last_x = e.x;
	last_y = e.y;

	// right button pressed
	if(e.state & SDL_BUTTON(3))
	{
		if(reg_sf->w < screen->w)
			rel_x = 0;
		else if(rel_x + xrel > 0)
			rel_x = 0;
		else if(rel_x + xrel < (screen->w - reg_sf->w))
			rel_x = (screen->w - reg_sf->w);
		else
			rel_x += xrel;

		if(reg_sf->h < screen->h)
			rel_y = 0;
		else if(rel_y + yrel > 0)
			rel_y = 0;
		else if(rel_y + yrel < (screen->h - reg_sf->h))
			rel_y = (screen->h - reg_sf->h);
		else
			rel_y += yrel;
	}
}


// User clicked on "reboot region"
void reboot_region()
{
	if(question(QUESTION, false, _("Are you sure you want to reboot this region? All the cities contained in it will be destroyed!")))
	{
		region = region_reboot(region);
		draw_region();
		draw_screen();
	}
}


// user clicked on "delete region"
void delete_region()
{
	if(question(QUESTION, false, _("Are you sure you want to delete this region?")))
	{
		region_delete(region);
		region = NULL;
	}
}


// user clicked on "rename region"
void rename_region()
{
	bool reply;
	char name[30];
again:
	reply = input(QUESTION, name, 30, true, 
			_("What will be the new name of the region?"));
	if(!reply)
		return;
	if(strcmp(name, "") == 0)
	{
		message(WARNING, "Please give a name to the region.");
		goto again;
	}
	region_rename(region, name);

	// rebuild region name
	Pencil p = { screen, editundo14, (SDL_Color){255,255,255}, (SDL_Color){0,0,0}};
	region_name = dbl_text(p, 0, region->name);
	draw_screen();
}


// user clicked on "back to main menu"
void back()
{
	region_free(region);
	region = NULL;
}


// Free all memory that was allocated by this screen.
static void free_ui_region()
{
	if(reg_sf)
		SDL_FreeSurface(reg_sf);
	if(region_name)
		SDL_FreeSurface(region_name);
	if(msg)
		SDL_FreeSurface(msg);
}


// Main function - display the region chooser and parse the events.
City* show_ui_region(Region* r)
{
	region = r;
	rel_x = rel_y = 0;
	last_x = last_y = 0;

	initialize_images();
	setup_ui_region_palette();
	draw_region();

resize:
	SDL_FillRect(screen, NULL, R_BACKGROUND);

	while(!chosen_city)
	{
		Uint32 next = SDL_GetTicks() + (1000/60);

		// drawing
		draw_screen();
	
		// controls
		SDL_Event e;
		while(SDL_PollEvent(&e))
			switch(e.type)
			{
				case SDL_MOUSEBUTTONDOWN:
					if(e.button.button == SDL_BUTTON_LEFT)
						mouse_button(e.button);
					break;
				case SDL_MOUSEMOTION:
					mouse_motion(e.motion);
					break;
				case SDL_VIDEORESIZE:
					screen = SDL_SetVideoMode(e.resize.w, 
							e.resize.h, 8, 
							screen->flags);
					SDL_SetPalette(screen, 
							SDL_LOGPAL|SDL_PHYSPAL, 
							color, 0, 255);
					goto resize;
					break;
				case SDL_QUIT:
					{
						atexit(SDL_Quit);
						exit(0);
					}
					break;
			}

		// timer
		while(SDL_GetTicks() < next)
			SDL_Delay(1);

		// rotate water palette
		water_cycle(water);
		SDL_SetPalette(reg_sf, SDL_LOGPAL|SDL_PHYSPAL, color, 0, 255);

		// check if region was deleted
		if(!region)
			return NULL;
	}

	free_ui_region();
	return chosen_city;
}
